package demo.mianshi.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class _生产消费 {
    public static void main(String[] args) {
        /**
         *  蜜蜂是生产者，熊是消费者。蜜蜂生产蜂蜜是累加的过程，
         *   熊吃蜂蜜是批量（满100吃掉）的过程。
         *   生产者和消费者之间使用通知方式告知对方。注意不能出现死锁的现象。
         *   100只蜜蜂，每次生产的蜂蜜是1.
         *   熊吃蜂蜜是20（批量的情况）。
         */
        HoneyProduction production = new HoneyProduction();
        new Bear(production).start();
        for (int i = 0; i < 100; i++) {
            new Bee(production, i).start();
        }

    }

    // 蜂蜜生产
    static class HoneyProduction {
        private static final int bear_eat = 20;// 熊每次吃20
        private static final int bee = 100;// 蜜蜂
        private static final int honey_max = 100;// 蜂蜜
        private int honey = 0;
        private Lock lock = new ReentrantLock();
        private Condition notFull = lock.newCondition();// 蜂蜜未满
        private Condition full = lock.newCondition();// 蜂蜜满唤醒熊


        // 生产蜂蜜
        public void product(int beeId) {
            lock.lock();
            try {
                // 蜂蜜满 通知熊吃
                while (honey >= honey_max) {
                    notFull.await();
                }
                // 生产1
                honey++;
                System.out.println("蜜蜂:" + beeId + "生产1个，当前蜂蜜:" + honey + "/" + honey_max);
                // 蜂蜜满100
                if (honey == honey_max) {
                    System.out.println("蜂蜜已满，唤醒熊");
                    full.signal();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }

        }

        public void eat() throws InterruptedException {
            lock.lock();
            // 等待蜂蜜达到100
            try {
                while (honey <= 0) {
                    System.out.println("蜂蜜吃光了，熊停止吃");
                    full.await();
                }
                int eat = Math.min(honey, bear_eat);
                honey -= eat;
                System.out.println("熊吃了" + eat + "蜂蜜,剩余蜂蜜" + honey + "/" + honey_max);
                notFull.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }

    static class Bee extends Thread {
        private HoneyProduction production;
        private int beeId;

        public Bee(HoneyProduction honeyProduction, int beeId) {
            this.production = honeyProduction;
            this.beeId = beeId;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    // 生产蜂蜜
                    production.product(beeId);
                    //
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Bear extends Thread {
        private HoneyProduction production;

        public Bear(HoneyProduction production) {
            this.production = production;
        }

        @Override
        public void run() {
            // 吃蜂蜜
            while (true) {
                try {
                    production.eat();
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
